home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 24 / develop Issue 24 code / Scriptable Database 1.0a15 / Database / DBRecord.h < prev    next >
Encoding:
Text File  |  1996-04-25  |  15.5 KB  |  397 lines  |  [TEXT/CWIE]

  1. //================================================================================
  2. // Greg Anderson
  3. // db+
  4. //
  5. // Cursor to an database record record
  6. // 16 May 1994
  7. //================================================================================
  8. #pragma once
  9.  
  10. #ifndef __ABSTRACTDBRECORD__
  11. #define __ABSTRACTDBRECORD__
  12.  
  13. //
  14. // Abstract cursor is the base class for TDBRecord
  15. //
  16. #include "AbstractRecord.h"
  17.  
  18. //
  19. // For CompareEnumeration
  20. //
  21. #include "AbstractData.h"
  22.  
  23. //
  24. // For REQUIREVALIDPOINTER
  25. //
  26. #include "Exceptions.h"
  27.  
  28. //
  29. // There are some fields common to both object records and property
  30. // records.  Why have two abstract classes rather than define these
  31. // methods in TAbstractRecord?  The only reason is to keep all
  32. // knowledge of the type of information in the records out of the
  33. // low level interface and up in the middle level interface.
  34. //
  35. // Fields:
  36. //
  37. //        Flags
  38. //        Parent sibling
  39. //        Left sibling
  40. //        Right sibling
  41. //        
  42. //        Next four longwords vary based on the type of the record
  43. //
  44. //        Identifier of data record or parent element of object record
  45. //        Data or index of record at top of element tree
  46. //        Data or index of record at top of property tree
  47. //        Data or index of name property
  48. //
  49. // Flag bits:
  50. //
  51. //    DB Records:
  52. //
  53. //        b31-b30:    AVL balance factor (left high, equal, right high)
  54. //        b29:        Set = record is at top of tree, clear = record is a sub-node
  55. //
  56. //    Object records:
  57. //
  58. //        b28:        Clear = object record (set = some other kind of record)
  59. //        b27-b0:        Node number
  60. //
  61. //    Data records:
  62. //
  63. //        b28:        Set
  64. //        b27:        Clear = data record (set = some other kind of record)
  65. //        b26-b16:    Unused
  66. //        b15-b8:     Encoded data type
  67. //         b7-b0:        Length of data (or zero if not applicable)
  68. //
  69. //        So far, b28 & b27 set is an undefined combination unless ALL bits in
  70. //        the flag word are set (which indicates a free DB record)
  71. //
  72. //         Important:    The first two bits of the flags longword must be nonzero,
  73. //                    as 00 identifies a block data record (see GroupControlObject.h)
  74. //
  75.  
  76. enum
  77. {
  78.     kRecordFlagsWord = 0,
  79.     kParentSiblingWord,
  80.     kLeftSiblingWord,
  81.     kRightSiblingWord,
  82.     
  83.     kIDOrParentElementIndex,
  84.     kNamePropertyWord,
  85.     kTopPropertyWord,
  86.     kTopChildWord
  87. };
  88.  
  89. //
  90. // Flag bits:
  91. //
  92. enum
  93. {
  94.     kBalanceFactorBits                        = 0xC0000000,
  95.         kLeftSideHigher                            = 0x80000000,
  96.         kSubtreesBalanced                        = 0xC0000000,
  97.         kRightSideHigher                        = 0x40000000,
  98.     kTopOfTreeBit                            = 0x20000000,
  99.     kObjectRecordDefinitionBit                = 0x10000000,        // CLEAR for object records
  100.         kObjectRecordReservedRecordBits            = 0x0FFFFFFF,
  101.     kDataRecordDefinitionBit                = 0x08000000,        // CLEAR for data records
  102.         kDataRecordReservedRecordBits            = 0x07FFFFFF
  103. };
  104.  
  105. //
  106. // Enumerations for initial values for flag bits
  107. //
  108. // Note that in the initial object record flags, kObjectRecordDefinitionBit is CLEAR
  109. // and in the initial data record flags, kDataRecordDefinitionBit is CLEAR
  110. //
  111. enum
  112. {
  113.     kInitialObjectRecordFlags                = (kSubtreesBalanced | kTopOfTreeBit),
  114.     kInitialDataRecordFlags                    = (kSubtreesBalanced | kObjectRecordDefinitionBit | kTopOfTreeBit)
  115. };
  116.  
  117.  
  118. enum ChildIdentifier
  119. {
  120.     kNodeIsLeftChild,
  121.     kNodeIsRightChild,
  122.     kNodeIsTopOfElementTree,
  123.     kNodeIsTopOfPropertyTree,
  124.     kNodeIsNotAChild
  125. };
  126.  
  127. class TAbstractDBComparisonObject;
  128.  
  129. //================================================================================
  130. // Class TDBRecord
  131. //================================================================================
  132. class TDBRecord : public TAbstractRecord
  133. {
  134.     //
  135.     // ----- Fields --------------------------------------------------------------
  136.     //
  137. protected:
  138.     
  139.     //
  140.     // ----- Methods -------------------------------------------------------------
  141.     //
  142.  
  143. public:
  144.                                     TDBRecord(TDatabaseDocument* doc, long recordIndex) :
  145.                                         TAbstractRecord(doc, recordIndex) {};
  146.     virtual                            ~TDBRecord();
  147.  
  148.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  149.     // Methods of TAbstractRecord:
  150.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  151.  
  152. public:
  153.  
  154.     virtual void                    FreeOwnedData(TTransaction* t);
  155.     virtual void                    FreeThisRecord(TTransaction* t);
  156.  
  157. protected:
  158.  
  159.     virtual const TDBRecord* AbstractDBRecord() const { return this; };
  160.     
  161.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  162.     // Public interface:  const methods
  163.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  164.  
  165. public:
  166.     
  167.     //
  168.     // Basic navagation:
  169.     //
  170.     virtual AConst<TDBRecord>        TreeOwner(TTransaction* t) const;
  171.     AConst<TDBRecord>                FirstItemInTree(TTransaction* t) const;
  172.     AConst<TDBRecord>                LastItemInTree(TTransaction* t) const;
  173.     AConst<TDBRecord>                NextItemInTree(TTransaction* t) const;
  174.     AConst<TDBRecord>                PreviousItemInTree(TTransaction* t) const;
  175.  
  176.     AConst<TDBRecord>                FindItemInTree(TTransaction* t, TAbstractDBComparisonObject* doCompare) const;
  177.  
  178.     //
  179.     // Subtree searching:  Probably not generally useful, but slightly faster if
  180.     // you know you already have the top item in the tree
  181.     //
  182.     AConst<TDBRecord>                FirstItemInSubTree(TTransaction* t) const;
  183.     AConst<TDBRecord>                LastItemInSubTree(TTransaction* t) const;
  184.     AConst<TDBRecord>                FindItemInSubTree(TTransaction* t, TAbstractDBComparisonObject* doCompare) const;
  185.  
  186.     //
  187.     // Navigation methods most people won't need to use
  188.     //
  189.     AConst<TDBRecord>                TopOfTree(TTransaction* t) const;
  190.     AConst<TDBRecord>                LeftSibling(TTransaction* t) const                { return this->GetDBRecordCursor(this->LeftSiblingIndex(t)); }
  191.     AConst<TDBRecord>                RightSibling(TTransaction* t) const                { return this->GetDBRecordCursor(this->RightSiblingIndex(t)); }
  192.     AConst<TDBRecord>                ParentSibling(TTransaction* t) const            { return this->RecordIsAtTopOfTree(t) ? AConst<TDBRecord>(nil) : LiteralParentSibling(t); }
  193.     
  194.     //
  195.     // Tests to do before navagation, if you'd like to peek before going there:
  196.     //
  197.     Boolean                            RecordIsInATree(TTransaction* t) const            { return this->ParentSiblingIndex(t) != kNilIndex; }
  198.     Boolean                            RecordIsAtTopOfTree(TTransaction* t) const        { return (this->RecordFlags(t) & kTopOfTreeBit) != 0; }
  199.     Boolean                            HasLeftSibling(TTransaction* t) const            { return this->LeftSiblingIndex(t) != kNilIndex; }
  200.     Boolean                            HasRightSibling(TTransaction* t) const            { return this->RightSiblingIndex(t) != kNilIndex; }
  201.     long                            NumberOfChildSiblings(TTransaction* t) const;
  202.     
  203.     //
  204.     // Usually you should use the more specific routines for accessing
  205.     // the elements or properties of a record; see TDBElement
  206.     //
  207.     AConst<TDBRecord>                TopElementRecord(TTransaction* t) const            { return this->GetDBRecordCursor(this->TopChildIndex(t)); };
  208.     AConst<TDBRecord>                TopPropertyRecord(TTransaction* t) const        { return this->GetDBRecordCursor(this->TopPropertyIndex(t)); };
  209.     
  210.     //
  211.     // Now we're getting so obscure, this should almost be in the protected interface.
  212.     // Avoid calling these routines.
  213.     //
  214.     AConst<TDBRecord>                LiteralParentSibling(TTransaction* t) const        { return this->GetDBRecordCursor(this->ParentSiblingIndex(t)); };
  215.     AConst<TDBRecord>                GoUpUntil(TTransaction* t, ChildIdentifier fromDirection) const;
  216.     virtual ChildIdentifier            IdentifyChild(TTransaction* t, AConst<TDBRecord>) const;
  217.  
  218.     //
  219.     // CompareSortKeys should compare the keys of the two nodes and return
  220.     // whether the second is larger, smaller or equal than the first.
  221.     //
  222.     // CompareTreeOrder does the same thing as CompareSortKeys, but it is
  223.     // _never_ allowed to return equal; one node must always be larger than
  224.     // the other.
  225.     //
  226.     virtual CompareEnumeration        CompareSortKeys(TTransaction* t, AConst<TDBRecord> secondObject) const = 0;
  227.     virtual CompareEnumeration        CompareTreeOrder(TTransaction* t, AConst<TDBRecord> secondObject) const;
  228.     static CompareEnumeration        DetermineCompareEnumeration(long key1, long key2) { return key2 < key1 ? kSecondObjectComesBefore : (key2 > key1 ? kSecondObjectComesAfter : kObjectKeysEqual ); };
  229.  
  230.     //
  231.     // Do debugging tests on this node
  232.     //
  233.     long                            DeepestSubtree(TTransaction* t) const;
  234.     virtual void                    Verify(TTransaction* t, Boolean verifyDeep = false) const;
  235.     
  236.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  237.     // Public interface:  non-const methods
  238.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  239.  
  240. public:
  241.  
  242.     Boolean                            Insert(TTransaction* t, AnUpdate<TDBRecord>);
  243.     virtual void                    RemoveFromTree(TTransaction* t);    
  244.     
  245.     //
  246.     // The method "ResortThisRecord" should be called whenever the sort key
  247.     // for this record changes; doing that removes and re-inserts this record
  248.     // in the tree it is currently contained in.  This is done automatically
  249.     // by TDBProperty, so this method should probably be protected.
  250.     //
  251.     void                            ResortThisRecord(TTransaction* t);
  252.     
  253.     //
  254.     // Usually, only the database document will call this method;
  255.     // use TDatabaseDocument::NewDBProperty(TTransaction*) and
  256.     // TDatabaseDocument::NewDBElement(TTransaction*) to get new
  257.     // database records to work with
  258.     //
  259.     virtual void                    InitializeNewRecord(TTransaction* t);
  260.     
  261.     //
  262.     // Usually, only a property record will call this method
  263.     //
  264.     virtual void                    PropertyValueChanged(TTransaction* t, AConst<TDBProperty> propertyThatChanged);
  265.     
  266.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  267.     // Protected interface:  const methods
  268.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  269.  
  270. protected:
  271.     
  272.     long                            RecordFlags(TTransaction* t) const                 { return this->GetRecordData(t, kRecordFlagsWord); };
  273.     long                            ParentSiblingIndex(TTransaction* t) const         { return this->GetRecordData(t, kParentSiblingWord); };
  274.     long                            LeftSiblingIndex(TTransaction* t) const         { return this->GetRecordData(t, kLeftSiblingWord); };
  275.     long                            RightSiblingIndex(TTransaction* t) const         { return this->GetRecordData(t, kRightSiblingWord); };
  276.  
  277.     //
  278.     // Usually, only object records own children and property trees.
  279.     // However, there are some types of data records that may also own
  280.     // trees; when they do, their pointer to the top record of the tree
  281.     // is always in the same index as the same field in an object
  282.     // record.  Therefore, we abstract these field as if it were a
  283.     // member of every DB cursor, even though they might not exist in
  284.     // some records.
  285.     //
  286.     // RequireRecordCanHaveElements / RequireRecordCanHaveProperties
  287.     // will fail if the record cannot contain elements/properties,
  288.     // or do nothing if elements/properties are okay
  289.     //
  290.     virtual Boolean                    RecordCanHaveElements(TTransaction* t) const;
  291.     virtual Boolean                    RecordCanHaveProperties(TTransaction* t) const;
  292.     void                            RequireRecordCanHaveElements(TTransaction* t) const;
  293.     void                            RequireRecordCanHaveProperties(TTransaction* t) const;
  294.     
  295.     long                            TopChildIndex(TTransaction* t) const            { this->RequireRecordCanHaveElements(t); return this->GetRecordData(t, kTopChildWord); };
  296.     long                            TopPropertyIndex(TTransaction* t) const            { this->RequireRecordCanHaveProperties(t); return this->GetRecordData(t, kTopPropertyWord); };
  297.  
  298.     long                            BalanceFactor(TTransaction* t) const            { return this->RecordFlags(t) & kBalanceFactorBits; };
  299.  
  300.     virtual long                    FreeListToUse(TTransaction*) { return 0; } // we have a constant for this "0" (kFreeRecordListIndex), but right now it's in RecordGroupControlObject.h
  301.  
  302.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  303.     // Protected interface:  non-const methods
  304.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  305.  
  306. protected:
  307.  
  308.     void                            SetRecordFlags(TTransaction* t, long newValue)            { this->ChangeRecordData(t, kRecordFlagsWord, newValue); };
  309.     void                            SetParentSiblingIndex(TTransaction* t, long newValue)    { this->ChangeRecordData(t, kParentSiblingWord, newValue); };
  310.     void                            SetLeftSiblingIndex(TTransaction* t, long newValue)        { this->ChangeRecordData(t, kLeftSiblingWord, newValue); };
  311.     void                            SetRightSiblingIndex(TTransaction* t, long newValue)        { this->ChangeRecordData(t, kRightSiblingWord, newValue); };
  312.  
  313.     void                            SetRecordIsAtTopOfTree(TTransaction* t, Boolean atTop)    { this->SetRecordFlags(t, (this->RecordFlags(t) & ~kTopOfTreeBit) | (atTop ? kTopOfTreeBit : 0)); };
  314.     void                            SetBalanceFactor(TTransaction* t, long newFactor)        { this->SetRecordFlags(t, (this->RecordFlags(t) & ~kBalanceFactorBits) | (newFactor & kBalanceFactorBits)); };
  315.  
  316.     void                            SetTopChildIndex(TTransaction* t, long newValue)        { this->RequireRecordCanHaveElements(t); this->ChangeRecordData(t, kTopChildWord, newValue); };
  317.     void                            SetTopPropertyIndex(TTransaction* t, long newValue)        { this->RequireRecordCanHaveProperties(t); this->ChangeRecordData(t, kTopPropertyWord, newValue); };
  318.  
  319.     void                            SetLeftSibling(TTransaction* t, AConst<TDBRecord> cursor)        { this->SetLeftSiblingIndex(t, cursor.Exists() ? cursor->RecordIndex() : kNilIndex); };
  320.     void                            SetRightSibling(TTransaction* t, AConst<TDBRecord> cursor)        { this->SetRightSiblingIndex(t, cursor.Exists() ? cursor->RecordIndex() : kNilIndex); };
  321.     void                            SetParentSibling(TTransaction* t, AConst<TDBRecord> cursor)        { this->SetParentSiblingIndex(t, cursor.Exists() ? cursor->RecordIndex() : kNilIndex); };
  322.     void                            SetElements(TTransaction* t, AConst<TDBRecord> cursor)            { this->SetTopChildIndex(t, cursor.Exists() ? cursor->RecordIndex() : kNilIndex); };
  323.     void                            SetProperties(TTransaction* t, AConst<TDBRecord> cursor)        { this->SetTopPropertyIndex(t, cursor.Exists() ? cursor->RecordIndex() : kNilIndex); };
  324.     
  325.     void                            SetChildLinkOfNewParent(TTransaction* t, AConst<TDBRecord> newChild, ChildIdentifier whichChild);
  326.     ChildIdentifier                    SetParentsLinkToThisNodeTo(TTransaction* t, AConst<TDBRecord> newChild);
  327.     void                            SwapTreePositions(TTransaction* t, AnUpdate<TDBRecord> swapWith);
  328.  
  329.     void                            FreeEntireTree(TTransaction* t);
  330.         
  331.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  332.     // Private methods:
  333.     //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  334.  
  335. private:
  336.     void                            RightBalance(TTransaction* t);
  337.     void                            LeftBalance(TTransaction* t);
  338.     void                            RotateLeft(TTransaction* t);
  339.     void                            RotateRight(TTransaction* t);
  340.     void                            DoubleRotateRightSide(TTransaction* t);
  341.     void                            DoubleRotateLeftSide(TTransaction* t);
  342. };
  343.  
  344. //================================================================================
  345. // Class TAbstractDBComparisonObject
  346. //================================================================================
  347. class TAbstractDBComparisonObject
  348. {
  349. public:
  350.     virtual CompareEnumeration    TestObject(TTransaction*, AConst<TDBRecord>) = 0;
  351. };
  352.  
  353. //
  354. // Iteration direction
  355. //
  356. enum
  357. {
  358.     kIterateForward = 0,
  359.     kIterateBackward
  360. };
  361.  
  362. //================================================================================
  363. // Class TAbstractRecordIterator
  364. //
  365. // Give the constructor a AConst<TDBRecord>, and the iterator will iterate over
  366. // all of the siblings of the record + the record itself.  So, to iterate over
  367. // the properties of a record:
  368. //
  369. //        properties = cursor->Properties();
  370. //        for(TAbstractRecordIterator iter(properties); iter.More(); iter.Next())
  371. //            ... do stuff
  372. //================================================================================
  373. class TAbstractRecordIterator
  374. {
  375. private:
  376.     AConst<TDBRecord>            fCursor;
  377.     AConst<TDBRecord>            fCurrent;
  378.     Boolean                        fDirection;
  379.     Boolean                        fHaveRemovedCurrent;
  380.     TTransaction*                fTransaction;
  381.     
  382. public:
  383.             TAbstractRecordIterator(TTransaction* t, AConst<TDBRecord> cursor, Boolean = kIterateForward);
  384.     virtual    ~TAbstractRecordIterator();
  385.         
  386.     Boolean                        IterateForward() const    { return fDirection == kIterateForward; }
  387.     void                        Reset(Boolean direction = kIterateForward);
  388.     Boolean                        More() const            { return fCurrent.Exists(); }
  389.     void                        Next();
  390.     void                        RemoveCurrent();
  391.     
  392.     AConst<TDBRecord>            Current() { return fCurrent; }
  393.     TTransaction*                Transaction() { return fTransaction; }
  394. };
  395.  
  396. #endif
  397.